package cn.itsource.service.impl;
import cn.dev33.satoken.stp.SaLoginConfig;
import cn.dev33.satoken.stp.StpUtil;
import cn.itsource.constants.CacheConstants;
import cn.itsource.constants.Constants;
import cn.itsource.constants.ErrorCode;
import cn.itsource.constants.RConst;
import cn.itsource.exception.GlobalException;
import cn.itsource.mapper.LoginMapper;
import cn.itsource.pojo.domain.Login;
import cn.itsource.pojo.domain.Permission;
import cn.itsource.pojo.domain.Role;
import cn.itsource.pojo.dto.LoginAdminDto;
import cn.itsource.pojo.dto.LoginDto;
import cn.itsource.pojo.vo.LoginSuccessVo;
import cn.itsource.result.JSONResult;
import cn.itsource.service.ILoginService;

import cn.itsource.utils.AssertUtil;
import cn.itsource.wechatTemplate.WechatLoginTemplate;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 登录表 服务实现类
 * </p>
 *
 * @author yh
 * @since 2024-09-03
 */
@Service
public class LoginServiceImpl extends ServiceImpl<LoginMapper, Login> implements ILoginService {
    @Autowired
    private WechatLoginTemplate wechatLoginTemplate;

    @Autowired
    private LoginMapper loginMapper;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;


    @Override
    public JSONResult loginAdmin(LoginAdminDto adminDto) {
        Login login = loginMapper.selectOne(new LambdaQueryWrapper<Login>()
                .eq(Login::getUsername, adminDto.getUsername())
                .eq(Login::getType, RConst.Num.BASE_LONG_0));
        AssertUtil.isNotNull(login,"用户名或者密码错误");
        //验证密码对不对
        boolean matches = passwordEncoder.matches(adminDto.getPassword().trim(),
                login.getPassword());
        AssertUtil.isTrue(matches,"用户名或者密码错误");
        LoginSuccessVo loginSuccessVo = resultLogin(login);
        return JSONResult.success(loginSuccessVo);
    }

/*    @Override
    public JSONResult exit() {

    }*/

    private LoginSuccessVo resultLogin(Login login) {
        //返回token 和 一些基本信息
        StpUtil.login(login.getId(), SaLoginConfig.setExtra("currentUser", login));
        //加载权限 & 角色信息到redis里面
        List<String> permissionList = this.getPermissionByLoginId(login.getId());
        List<String> roleByLoginId = this.getRoleByLoginId(login.getId());
        //防止密码泄露
        login.setPassword(null);
        //创建一个返回对象
        LoginSuccessVo loginSuccess = LoginSuccessVo.builder()
                .phone(login.getPhone())
                .avatar(login.getAvatar())
                .login(login)
                .token(StpUtil.getTokenValue())
                .permissions(permissionList)
                .roles(roleByLoginId)
                .nickName(login.getNickName()).build();
        return loginSuccess;
    }
    @Override
    public JSONResult login(LoginDto loginDto) {
        String openId = wechatLoginTemplate.OpenId(loginDto.getCode());
        LambdaQueryWrapper<Login> wrapper = new LambdaQueryWrapper<Login>()
                .eq(Login::getOpenId, openId)
                        .eq(Login::getType, loginDto.getType());
        Login login = this.getOne(wrapper);
        if(login!=null){
            // 会话登录：参数填写要登录的账号id，建议的数据类型：long | int | String， 不可以传入复杂类型，如：User、Admin 等等
            StpUtil.login(login.getId(),SaLoginConfig.setExtra("currentUser",login));
           /* StpUtil.getSession().set("currentUser",login);*/
            LoginSuccessVo loginSuccess = LoginSuccessVo.builder()
                    .phone(login.getPhone())
                    .avatar(login.getAvatar())
                    .login(login)
                    .token(StpUtil.getTokenValue())
                    .nickName(login.getNickName()).build();

             this.getPermissionByLoginId(login.getId());
             this.getRoleByLoginId(login.getId());
             return JSONResult.success(loginSuccess);
        }
        else {
            throw new GlobalException(ErrorCode.NO_USER);
        }
    }

    @Override
    public List<String> getPermissionByLoginId(Long loginId) {
        String key=CacheConstants.CURRENT_USER_PERMISSION+loginId;
        if(redisTemplate.hasKey(key)){
           return (List<String>) redisTemplate.opsForValue().get(key);
        }

        redisTemplate.opsForValue().get(CacheConstants.CURRENT_USER_PERMISSION);
        List<Permission> permissions = loginMapper.getPermissionByLoginId(Long.valueOf(loginId.toString()));
        List<String> collect = permissions.stream().map(Permission::getSn).collect(Collectors.toList());
        //缓存到redis
        redisTemplate.opsForValue().set(key,collect, RConst.Num.INT_12, TimeUnit.HOURS);
        return collect;
    }

    @Override
    public List<String> getRoleByLoginId(Long loginId) {
        String key=CacheConstants.CURRENT_USER_ROLE+loginId;
        if (redisTemplate.hasKey(key)){
            return (List<String>) redisTemplate.opsForValue().get(key);
        }
        List<Role> roleByLoginId = loginMapper.getRoleByLoginId(loginId);
        List<String> collect = roleByLoginId.stream().map(Role::getSn).collect(Collectors.toList());
        redisTemplate.opsForValue().set(key,collect,RConst.Num.INT_12, TimeUnit.HOURS);
        return collect;
    }


}
